/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * 
 * Project Name:itsm-gateway
 * Create Time: 2016年1月30日 下午3:02:56
 */
package com.lenovo.lmrp.server.itsmgateway;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.Objects;

import javax.persistence.Entity;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.jboss.resteasy.plugins.guice.ext.RequestScopeModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.beust.jcommander.JCommander;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Scopes;
import com.lenovo.lmrp.base.ABaseMain;
import com.lenovo.lmrp.base.FTPService;
import com.lenovo.lmrp.base.FileSystemService;
import com.lenovo.lmrp.base.IFileService;
import com.lenovo.lmrp.base.ParamNameDef;
import com.lenovo.lmrp.server.itsmgateway.adapter.AItsmAdapterFactory;
import com.lenovo.lmrp.server.itsmgateway.repository.ARepositoryFactory;
import com.lenovo.lmrp.server.itsmgateway.spi.ItsmGatewayRestServer;
import com.lenovo.sdc.framework.dao.ADaoFactory;
import com.lenovo.sdc.framework.dao.HibernateDaoFactory;
import com.lenovo.sdc.framework.dao.NamedQueryFactory;
import com.lenovo.sdc.framework.mq.AMQClient;
import com.lenovo.sdc.framework.mq.MQFactory;
import com.lenovo.sdc.framework.mq.MQServerParam;
import com.lenovo.sdc.framework.mq.MQServerParam.MQProvider;
import com.lenovo.sdc.framework.util.AttributeBean;
import com.lenovo.sdc.framework.util.ClassScanner;

/**
 * 
 * @author wujin
 * @version v1.0
 */
public class ItsmGatewayMain extends ABaseMain {
    private static Logger logger = LoggerFactory.getLogger(ItsmGatewayMain.class);

    public static void main(String[] args) {
        ItsmGatewayMain server = new ItsmGatewayMain();
        JCommander commander = server.parseCommand(args);

        try {
            server.initialize();
            logger.info("ITSM Gateway Server startup");
        }
        catch (Exception exp) {
            System.out.println("failed to initialize ITSMGateway Server because " + exp.getMessage());
            exp.printStackTrace();
            commander.usage();
            System.exit(0);
        }
    }

    @Override
    public void initialize() throws Exception {
        // find itsmgateway.properties in class path then load data to create AttributeBean object
        AttributeBean params = loadProperties("itsmgateway.properties");
        logger.info("successed to load configuration parameters from itsmgateway.properties");
        
        // initialize DAOFacotry, load hibernateFile configuration file from class path
        initializeDAOFactory();
        logger.info("successed to initialized DAOFactory");
        
        // create Guice DI container
        Injector injector = Guice.createInjector(new RequestScopeModule(),
            
            new Module(){
            @Override
            public void configure(Binder binder) {
                // bind ITSM Configuration parameter to AttributeBean instance
                binder.bind(AttributeBean.class).toInstance(params);
                
                // bind MQClient as singleton instance
                MQServerParam mqparam = new MQServerParam(
                    MQProvider.valueOf(params.getAttribute(ParamNameDef.MQ_SERVER_TYPE, MQProvider.ZEROMQ.name())), 
                    params.getAttribute(ParamNameDef.MQ_SERVER_HOST, "localhost"), 
                    params.getAttribute(ParamNameDef.MQ_SERVER_PORT, ParamNameDef.MQ_DEFAULT_PORT));
                binder.bind(AMQClient.class).toInstance(new MQFactory(mqparam).createMQClient());
                
                // bind IFileService as singleton instance
                if (params.getAttribute(ParamNameDef.FILE_SERVER_TYPE, ParamNameDef.LOCAL_FILE_SERVER)
                                .equalsIgnoreCase(ParamNameDef.LOCAL_FILE_SERVER))
                    binder.bind(IFileService.class).toInstance(new FileSystemService(params));
                else
                    binder.bind(IFileService.class).toInstance(new FTPService(params));
                
                binder.install(new ARepositoryFactory.RepositoryModule());
                
                binder.install(new AItsmAdapterFactory.AItsmAdapterModule());
                
                binder.bind(ItsmGatewayRestServer.class).in(Scopes.SINGLETON);
            }});
        
        logger.info("successed to setup DI Container");
        
        // start ItsmGatewayService, use Guice to inject configuration parameter
        ItsmGatewayRestServer rs = injector.getInstance(ItsmGatewayRestServer.class);
        rs.start();
        logger.info("successed to deploy Rest API Service");
        
        // create ITSM Adapter factory and load all eanbled adapter
        AItsmAdapterFactory adapterFacotry = injector.getInstance(AItsmAdapterFactory.class);
        adapterFacotry.initialize();
        logger.info("successed to initialize ITSM Adapter Factory");
    }

    public void initializeDAOFactory() throws Exception {
        File configFile = getConfigurationFile("hibernate.cfg.xml");
        if (configFile.exists() == false)
            throw new FileNotFoundException("not found configuration file " + configFile.getAbsolutePath());

        // create Hibernate configuration object
        Configuration config = new Configuration().configure(configFile);

        // scan package to get PO entity class and add to Hibernate manager
        ClassScanner scanner = new ClassScanner();
        List<Class<?>> classes = scanner.scanning("com.lenovo.lmrp.api.model.entity", true);
        classes.forEach(clz -> {
            if (Objects.nonNull(clz.getAnnotation(Entity.class)))
                config.addAnnotatedClass(clz);
        });

        // create hibernate session factory then create HibernateDaoFactory
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(config.getProperties())
            .build();
        SessionFactory sf = config.buildSessionFactory(serviceRegistry);
        
        // create named query factory that will scan sql directory
        NamedQueryFactory nqf = new NamedQueryFactory();
        nqf.setScanPath("classpath:/sql");
        nqf.afterPropertiesSet();
        
        ADaoFactory.setDefaultFactory(new HibernateDaoFactory(sf, nqf, true));
    }
}
